Skip to content

perf: speed up testplane launch#1115

Closed
KuznetsovRoman wants to merge 13 commits into
masterfrom
TESTPLANE-510.speed_up
Closed

perf: speed up testplane launch#1115
KuznetsovRoman wants to merge 13 commits into
masterfrom
TESTPLANE-510.speed_up

Conversation

@KuznetsovRoman

Copy link
Copy Markdown
Member

No description provided.

@pkg-pr-new

pkg-pr-new Bot commented Jul 25, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/gemini-testing/testplane@1115

commit: 91cafec

@KuznetsovRoman KuznetsovRoman force-pushed the TESTPLANE-510.speed_up branch 4 times, most recently from 1fbdabb to 7838f1d Compare July 28, 2025 16:31
Comment thread package.json
"gemini-configparser": "1.4.1",
"get-port": "5.1.1",
"import-meta-resolve": "4.0.0",
"load-esm": "1.0.2",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contains like 1 LOC:

module.exports = { loadEsm: (module) => import(module) };

In our project, typescript compiles all "import" to "require" and we can't prevent it
So, this package is used

export const MIN_CHROMIUM_VERSION = 73;
export const MIN_FIREFOX_VERSION = 60;
export const MIN_EDGEDRIVER_VERSION = 94;
export const DRIVER_WAIT_INTERVAL = 25; // 20ms

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are almost blocked while waiting for webdriver launch
Checking "if port is busy" more often saves some time by price of some CPU cycles

}

async getBrowser(id: string, opts: BrowserOpts = {}): Promise<NewBrowser> {
const { NewBrowser } = await import("../browser/new-browser");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"NewBrowser" takes some time to import
using lazy-load here (and in many other places) to reduce "time to require" and therefore - time to start workers, which is crucial

@@ -1,4 +1,4 @@
import { ImageInfo, RefImageInfo } from "../../../../types";
import type { ImageInfo, RefImageInfo } from "../../../../types";

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"import" -> "import type" also saves some time


saveDiffTo(diffPath: string): Promise<null> {
return Image.buildDiff({ diff: diffPath, ...this.diffOpts });
return import("../../../../image").then(m => m.Image.buildDiff({ diff: diffPath, ...this.diffOpts }));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Image" is fat, and we dont need to requrie "Image" module every time

import { loadEsm } from "load-esm";

export const preloadWebdriverIO = async (): Promise<void> => {
await loadEsm("@testplane/webdriverio").catch(() => {});

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require("@testplane/webdriverio") is cheap because it does not compile almost any of wdio code:

exports.remote = async function(params, remoteModifier) {
  const { remote } = await import("./node.js");
  return remote(params, remoteModifier);
};

Comment thread src/utils/processor.js
Comment on lines +26 to +28
preloadMochaReader();
preloadTestTransformer();
preloadWebdriverIO();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worker has some spare time, before master didn't send "runTest" command

Comment thread src/utils/workers-registry.js Outdated
Comment on lines +49 to +50
register(workerFilepath, exportedMethods) {
this._workerFarm.loadModule(workerFilepath, _.noop);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before:

  • "workerFilePath" is compiled only on call

after:

  • "workerFilePath" is compiled on register, so method would be called earlier

Comment on lines +43 to +45
runner.prepareBrowser({ sessionId, sessionCaps, sessionOpts, state });

const tests = await this._testParser.parse({ file, browserId });

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in worker, preparing browser does not depend on test
so we can start preparing browser before parsing test file

this._test.testplaneCtx = _.cloneDeep(test.testplaneCtx) || {};
}

async prepareBrowser({ sessionId, sessionCaps, sessionOpts, state }) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

floating promise, but does not throw
throws on "prepareToRun" with test and tool context to save compatibility

@KuznetsovRoman KuznetsovRoman force-pushed the TESTPLANE-510.speed_up branch 4 times, most recently from c30dd64 to c1fd802 Compare July 29, 2025 14:59
Comment on lines +146 to +153
const session = await WebDriver.newSession(fullSessionOpts);

const detectedSessionEnvFlags = sessionEnvironmentDetector({
capabilities: session.capabilities,
requestedCapabilities: fullSessionOpts.capabilities,
});

return attach({

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we waiting webdriver session, webdriverio is being preloaded (preloading started after workers are created)
unfortunately, we have to use wdio even in master, because SESSION_START is emitted from master:
https://testplane.io/docs/v8/reference/testplane-events/#session_start

@KuznetsovRoman KuznetsovRoman force-pushed the TESTPLANE-510.speed_up branch from c1fd802 to 86a2e95 Compare July 29, 2025 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant